#pragma once
#define WIN32_LEAN_AND_MEAN
#include <random>
#include "windows.h"
#include <iostream>
#include "MMSystem.h"
#include "d3dApp.h"
#include <time.h>
#include "CollisionTest.h"
#include "GraphicalEntity.h"
#include "PhysicsObjects.h"
#include "Missile.h"
#include "Thruster.h"
#include "Skybox.h"
#include "Planet.h"
#include "Ship.h"
#include "Bot.h"
#include "Railgun.h"
#include "GlobalInstances.h"
#include "Soundclass.h"

#define MOUSESENSITIVITYX 2.0f
#define MOUSESENSITIVITYY 2.0f


float DegToRad(float Degrees);
float RadToDeg(float Radians);

enum GameType
{
	Game = 0,
	MainMenu = 1,
};

struct _Score
{
	int PlayerScore;
	int BotScore;

	_Score()
	{
		PlayerScore = 0;
		BotScore = 0;
	}
};

struct _MenuItem
{
	bool IsSelected;
	D3DXVECTOR3 Position;
	IDirect3DTexture9 *ActivatedTexture;
	IDirect3DTexture9 *DeactivatedTexture;
};

struct _Camera
{
	D3DXVECTOR3 Position;
	D3DXVECTOR3 Angles;
	D3DXVECTOR3 Up;
	D3DXMATRIX RotMat;

	//Constructors
	_Camera()
	{
		Position = D3DXVECTOR3(0,0,0);
		Angles = D3DXVECTOR3(0,0, 0);
		RotMat = D3DXMATRIX(1,0,0,0,
							0,1,0,0,
							0,0,1,0,
							0,0,0,1);
	}

	_Camera(D3DXVECTOR3 nPosition, D3DXVECTOR3 nAngles)
	{
		Position = nPosition;
		Angles = nAngles;
		RotMat = D3DXMATRIX(1,0,0,0,
							0,1,0,0,
							0,0,1,0,
							0,0,0,1);
	}

	void SetPositionLocalCoord(D3DXVECTOR3 WorldVec)
	{
		D3DXVECTOR4 finalVec;
		D3DXVec3Transform(&finalVec, &WorldVec, &RotMat);
		Position = D3DXVECTOR3(Position.x + finalVec.x, Position.y + finalVec.y, Position.z + finalVec.z);
	}

	void SetAnglesLocalCoord(D3DXVECTOR3 nAngles, float dt)
	{

		if(Angles.y > DegToRad(10)  || Angles.y < DegToRad(-10))
			int i = 0;

		if(D3DXVec3LengthSq(&nAngles) != 1)
		{
			D3DXVec3Normalize(&nAngles, &nAngles);
		}

		D3DXVECTOR3 finalVec = nAngles;
		//D3DXMatrixRotationYawPitchRoll(&RotMat, Angles.x, Angles.y, Angles.z);
		D3DXVec3TransformCoord(&finalVec, &nAngles, &RotMat);

		if(finalVec.x < 0.00001 && finalVec.x > -0.00001)
			finalVec.x = 0;

		if(finalVec.y < 0.00001 && finalVec.y > -0.00001)
			finalVec.y = 0;

		if(finalVec.z < 0.00001 && finalVec.z > -0.00001)
			finalVec.z = 0;

		//finalVec *= dt;

		Angles += finalVec * dt;
	}

	void PrepareCamera(float MaxViewAngle, float MinViewAngle) //Prepares the camera for display
	{
		if(Angles.y > MaxViewAngle)
			Angles.y = MaxViewAngle;
		if(Angles.y < MinViewAngle)
			Angles.y = MinViewAngle;
	}

	void SetUpVector(D3DXVECTOR3 nUpVec)
	{
		Up = nUpVec;
	}
};

class CDirectXFramework : public D3DApp
{
	//TEST CODE
protected:
	//BaseMeshEntity* temp; //Doesn't work properly for some reason, 
						  //I am trying to use my own mesh/vertex structs
	//BaseIndexedGraphicalEntity *Cube;
	ID3DXEffect *tempRender;
	D3DXHANDLE Technique, WVPMat;
	
	ID3DXEffect *PlanetRender;
	D3DXHANDLE PlanetTechnique, PlanetWVPMat,
			   TextureHandle;

	int BoundMouseX, BoundMouseY;
	_Score Score;

	float Angle;
	ID3DXFont* ScoreFont;
#ifdef _DEBUG

	ID3DXFont *DebugFont;
	ID3DXSprite *FontSprite;

	short Throttle;

#endif
	//END TEST CODE

	float FOV;
	float Frames;
	float Time;

	GameType GameState;
	float LastStateSwitch;
	XINPUT_STATE *PlayerStates;

	ID3DXSprite *MenuSprite;
	IDirect3DTexture9 *BackgroundTex;
	IDirect3DTexture9 *CrossHairs;

	std::vector<_MenuItem*> MenuChoices;
	float MenuSwitch;
	UINT CurrentMenuChoice;

	RECT *WindowRectangle;

	//std::tr1::uniform_real<> *UniformRNG;
	std::tr1::mt19937 MersEngine;

	std::vector<Planet*> PlanetRenderList;

protected:
	_Camera *Camera;
	D3DXMATRIX ViewMat,
			   ProjMat;

private:
	void GameRender( void );
	void GameUpdate( float dt);
	void MenuRender( void );
	void MenuUpdate(float dt);
	bool LoadMenuItems( void );

	void GenerateWorld( void );
	void CreateAsteroidField( D3DXVECTOR3 Position, UINT radius, UINT Seed );
	void CreateDebrisField( D3DXVECTOR3 Positon, UINT radius, UINT Seed);

	D3DXVECTOR3 GetAPlanetaryRotation( void );
	D3DXVECTOR3 GetRandomDebrisRotation( void );
	D3DXVECTOR3 GetRandomAngle( void );

	D3DXVECTOR3 GetRandomPosition( UINT radius );


	bool AddPlanet( UINT Seed );
	bool AddBot( void );

	SoundClass* m_Sound; // Sound


public:
	CDirectXFramework();
	CDirectXFramework(HINSTANCE hInstance, std::string winCaption, D3DDEVTYPE devType, DWORD requestedVP);
	~CDirectXFramework();


	void LoadEntities( void );

	void SetupProjectionMatrix(); // Sets up the Projection matrix for the WVP matrix
	void LoadEffects();	// Loads up the effects, not modular yet
	void SetupCamera(); // Sets up the camera for the game
	bool checkDeviceCaps( void ); // Checks devices capabilities
	void onLostDevice( void );
	void onResetDevice( void );
	void updateScene(float dt); // Updates game logic
	void drawScene(); // Draws scene

	void ErrorMessage(std::string ErrorMessage);

	LRESULT CALLBACK MessageHandler(HWND,UINT,WPARAM,LPARAM);
	bool InitializeSound();
	void ShutdownSound();

private:
	LPCWSTR m_applicatioinName;
	HINSTANCE m_hinstance;
	HWND m_hwnd;

};

//extern _Globals *Globals;
static LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM);
static CDirectXFramework* ApplicationHandle=0;
